/**
 * @file drv_flash.c
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2024-11-16
 * 
 * @copyright Copyright (c) 2024
 * 
 */
#include "drv_flash.h"

static flash_inf_def g_flash_inf = {0};
static flash_ops_def g_flash_ops = {0};

/**
 * @brief 将flash内部数据读出并与目标数据比对
 * 
 * @param _uiSrcAddr flash地址
 * @param _ucpTar 目标数据地址
 * @param _uiSize 比较数据的长度
 * @return uint8_t 1：内容不同 0：内容相同
 */
static uint8_t fn_flash_cmp_data(uint32_t _uiSrcAddr, uint8_t *_ucpTar, uint32_t _uiSize)
{
	uint8_t temp_buffer[FLASH_CMP_BUF] = {0};
	uint16_t i, j ;
	uint16_t rem;

	/* 超出串行Flash地址空间，则直接返回 */
	if ((_uiSrcAddr + _uiSize) > g_flash_inf.TotalSize)
	{
		return 1;
	}

	/* 如果读取的数据长度为0直接返回 */
	if (_uiSize == 0)
	{
		return 0;
	}
	
	/* 整数 */
	for (i = 0; i < _uiSize / FLASH_CMP_BUF; i++)
	{		
		memset(temp_buffer, 0, FLASH_CMP_BUF);
		
		if ( g_flash_ops.drv_flash_read_buffer(temp_buffer, _uiSrcAddr + i * FLASH_CMP_BUF, FLASH_CMP_BUF) == false )
		{
			DRV_FLASH_LOG("\r\nflash read error 1, addr:%x size:%x\r\n", _uiSrcAddr + i * FLASH_CMP_BUF, FLASH_CMP_BUF);
			goto NOTEQ;
		}
		
		for (j = 0; j < FLASH_CMP_BUF; j++)
		{
			if (temp_buffer[j] != *_ucpTar++)
			{
				goto NOTEQ;	
			}
		}
	}
	
	/* 余数 */
	rem = _uiSize % FLASH_CMP_BUF;	
	if (rem > 0)
	{
		memset(temp_buffer, 0, FLASH_CMP_BUF);
		
		if (g_flash_ops.drv_flash_read_buffer(temp_buffer, _uiSrcAddr + i * FLASH_CMP_BUF, FLASH_CMP_BUF) == false)
		{
			DRV_FLASH_LOG("\r\nflash read error 2, addr:%x size:%x\r\n", _uiSrcAddr + i * FLASH_CMP_BUF, FLASH_CMP_BUF);
			goto NOTEQ;		
		}
		
		for (j = 0; j < rem; j++)
		{
			if (temp_buffer[j] != *_ucpTar++)
			{
				goto NOTEQ;		
			}
		}
	}
	return 0;		
	
NOTEQ:	
	return 1;
}

/**
 * @brief 判断是否需要擦除flash
 * 
 * @param _ucpOldBuf 已经存储的数据
 * @param _ucpNewBuf 新的数据
 * @param _usLen 长度
 * @return uint8_t 0 : 不需要擦除， 1 ：需要擦除
 */
static uint8_t fn_flash_need_erase(uint8_t * _ucpOldBuf, uint8_t *_ucpNewBuf, uint16_t _usLen)
{
	uint16_t i;
	uint8_t ucOld;

	/*
	算法第1步：old 求反, new 不变
	      old    new
		  1101   0101
	~     1111
		= 0010   0101

	算法第2步: old 求反的结果与 new 位与
		  0010   old
	&	  0101   new
		 =0000

	算法第3步: 结果为0,则表示无需擦除. 否则表示需要擦除
	*/
	for (i = 0; i < _usLen; i++)
	{
		ucOld = *_ucpOldBuf++;
		ucOld = ~ucOld;

		if ((ucOld & (*_ucpNewBuf++)) != 0)
		{
			return 1;
		}
	}
	return 0;
}

/**
 * @brief 单个扇区写入数据，自带擦除 
 * 
 * @param _ucpSrc 源数据地址
 * @param _uiWrAddr flash地址
 * @param _usWrLen 长度
 * @return uint8_t 1：成功 0：失败 
 */
static uint8_t fn_flash_write_sector_erase(uint8_t *_ucpSrc, uint32_t _uiWrAddr, uint16_t _usWrLen)
{
	uint16_t i;
	uint32_t uiFirstAddr;		
	uint8_t ucNeedErase;		
	uint8_t cRet;

	uint8_t *p_buff = g_flash_inf.cache_buff;
	
	/* 长度为0时不继续操作,直接认为成功 */
	if (_usWrLen == 0)
	{
		return 1;
	}

	/* 如果偏移地址超过芯片容量则退出 */
	if (_uiWrAddr >= g_flash_inf.TotalSize)
	{
		DRV_FLASH_LOG("\r\nwrite sector erase 1, addr:%x, size:%x\r\n", _uiWrAddr, g_flash_inf.TotalSize);
		return 0;
	}

	/* 如果数据长度大于扇区容量，则退出 */
	if (_usWrLen > g_flash_inf.SectorSize)
	{
		DRV_FLASH_LOG("\r\nwrite sector erase 2, _usWrLen:%d, SectorSize:%d\r\n", _usWrLen, g_flash_inf.SectorSize);
		return 0;
	}
	
	/* 读取数据出错，直接返回 */
	if (g_flash_ops.drv_flash_read_buffer(p_buff, _uiWrAddr, _usWrLen) == false)
	{
		DRV_FLASH_LOG("\r\nflash write error 3, addr:%x, size:%d\r\n", _uiWrAddr, _usWrLen);
		return 0;
	}
	
	/* 如果FLASH中的数据没有变化,则不写FLASH */
	if (memcmp(p_buff, _ucpSrc, _usWrLen) == 0)
	{
		return 1;
	}

	/* 判断是否需要先擦除扇区 */
	/* 如果旧数据修改为新数据，所有位均是 1->0 或者 0->0, 则无需擦除,提高Flash寿命 */
	ucNeedErase = 0;
	if (fn_flash_need_erase(p_buff, _ucpSrc, _usWrLen))
	{
		ucNeedErase = 1;
	}

	/* 算出第一个扇区地址 */
	uiFirstAddr = _uiWrAddr & (~(g_flash_inf.SectorSize - 1));

	if (_usWrLen == g_flash_inf.SectorSize)		/* 整个扇区都改写 */
	{
		for	(i = 0; i < g_flash_inf.SectorSize; i++)
		{
			p_buff[i] = _ucpSrc[i];
		}
	}
	else	
	{
		/* 先将整个扇区的数据读出 */
		if (g_flash_ops.drv_flash_read_buffer(p_buff, uiFirstAddr, g_flash_inf.SectorSize) == false)
		{
			DRV_FLASH_LOG("\r\nflash write error 4, addr:%x, size:%d\r\n", uiFirstAddr, g_flash_inf.SectorSize);
			return 0;
		}
		
		/* 再用新数据覆盖 */
		i = _uiWrAddr & (g_flash_inf.SectorSize - 1);
		memcpy(&p_buff[i], _ucpSrc, _usWrLen);
	}

	/* 写完之后进行校验，如果不正确则重写，最多2次 */
	cRet = 0;
	for (i = 0; i < FLASH_REWRITE; i++)
	{
		/* 如果旧数据修改为新数据，所有位均是 1->0 或者 0->0, 则无需擦除,提高Flash寿命 */
		if (ucNeedErase == 1)
		{
			/* 擦除1个扇区 */
			if (g_flash_ops.drv_flash_erase_sector(uiFirstAddr) == false)
			{
				DRV_FLASH_LOG("\r\nflash write error 5, addr:%x\r\n", uiFirstAddr);
				return 0;
			}
		}
		
		/* 编程一个扇区 */
		if (g_flash_ops.drv_flash_page_write(p_buff, uiFirstAddr, g_flash_inf.SectorSize) == false)
		{
			DRV_FLASH_LOG("\r\nflash write error 6, addr:%x, size:%d\r\n", uiFirstAddr, g_flash_inf.SectorSize);
			return 0;
		}		
		
		if (fn_flash_cmp_data(_uiWrAddr, _ucpSrc, _usWrLen) == 0)
		{
			cRet = 1;
			break;
		}
	}
	return cRet;
}

/**
 * @brief flash写入数据
 * 
 * @param _pBuf 源数据地址
 * @param _uiWriteAddr flash地址
 * @param _usWriteSize 数据长度
 * @return uint8_t 0：成功 <0：失败
 */
int drv_flash_write_buffer(uint8_t* _pBuf, uint32_t _uiWriteAddr, uint32_t _usWriteSize)
{
	uint32_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
	Addr = _uiWriteAddr % g_flash_inf.SectorSize;//起始地址
	count = g_flash_inf.SectorSize - Addr;//相对扇区未写入剩余长度
	NumOfPage =  _usWriteSize / g_flash_inf.SectorSize;//相对扇区整数
	NumOfSingle = _usWriteSize % g_flash_inf.SectorSize;//需要写入的相对扇区余数
	DRV_FLASH_LOG("fn_flash_write_buffer %x %d \n",_uiWriteAddr, _usWriteSize);
	
	if (Addr == 0) /* 起始地址是扇区首地址  */
	{
		if (NumOfPage == 0) /* 数据长度小于扇区大小 */
		{
			if (fn_flash_write_sector_erase(_pBuf, _uiWriteAddr, _usWriteSize) == 0)
			{
				DRV_FLASH_LOG("\r\nflash write error 1, addr:%x, size:%d\r\n", _uiWriteAddr, _usWriteSize);
				return -1;
			}
		}
		else 	/* 数据长度大于等于扇区大小 */
		{
			while (NumOfPage--)
			{
				if (fn_flash_write_sector_erase(_pBuf, _uiWriteAddr, g_flash_inf.SectorSize) == 0)
				{
					DRV_FLASH_LOG("\r\nflash write error 2, addr:%x, size:%d\r\n", _uiWriteAddr, g_flash_inf.SectorSize);
					return -2;
				}
				_uiWriteAddr +=  g_flash_inf.SectorSize;
				_pBuf += g_flash_inf.SectorSize;
			}
			
			if (NumOfSingle != 0)
			{
				if (fn_flash_write_sector_erase(_pBuf, _uiWriteAddr, NumOfSingle) == 0)
				{
					DRV_FLASH_LOG("\r\nflash write error 3, addr:%x, size:%d\r\n", _uiWriteAddr, NumOfSingle);
					return -3;
				}
			}
		}
	}
	else  /* 起始地址不是扇区首地址  */
	{
		if (NumOfPage == 0) /* 数据长度小于扇区大小 */
		{
			if (NumOfSingle > count)  /* 需要写入的长度大于当前扇区剩余长度 */
			{
				temp = NumOfSingle - count;

				if (fn_flash_write_sector_erase(_pBuf, _uiWriteAddr, count) == 0)
				{
					DRV_FLASH_LOG("\r\nflash write error 4, addr:%x, size:%d\r\n", _uiWriteAddr, count);
					return -4;
				}

				_uiWriteAddr +=  count;
				_pBuf += count;

				if (fn_flash_write_sector_erase(_pBuf, _uiWriteAddr, temp) == 0)
				{
					DRV_FLASH_LOG("\r\nflash write error 5, addr:%x, size:%d\r\n", _uiWriteAddr, temp);
					return -5;
				}
			}
			else
			{
				if (fn_flash_write_sector_erase(_pBuf, _uiWriteAddr, _usWriteSize) == 0)
				{
					DRV_FLASH_LOG("\r\nflash write error 6, addr:%x, size:%d\r\n", _uiWriteAddr, _usWriteSize);
					return -6;
				}
			}
		}
		else	/* 数据长度大于等于扇区大小 */
		{
			_usWriteSize -= count;
			NumOfPage =  _usWriteSize / g_flash_inf.SectorSize;
			NumOfSingle = _usWriteSize % g_flash_inf.SectorSize;

			/* 先写当前扇区剩余 */
			if (fn_flash_write_sector_erase(_pBuf, _uiWriteAddr, count) == 0)
			{
				DRV_FLASH_LOG("\r\nflash write error 7, addr:%x, size:%d\r\n", _uiWriteAddr, count);
				return -7;
			}

			_uiWriteAddr +=  count;
			_pBuf += count;

			/* 剩下的按照扇区整数和余数去写 */
			while (NumOfPage--)
			{
				if (fn_flash_write_sector_erase(_pBuf, _uiWriteAddr, g_flash_inf.SectorSize) == 0)
				{
					DRV_FLASH_LOG("\r\nflash write error 8, addr:%x, size:%d\r\n", _uiWriteAddr, g_flash_inf.SectorSize);
					return -8;
				}
				_uiWriteAddr +=  g_flash_inf.SectorSize;
				_pBuf += g_flash_inf.SectorSize;
			}

			if (NumOfSingle != 0)
			{
				if (fn_flash_write_sector_erase(_pBuf, _uiWriteAddr, NumOfSingle) == 0)
				{
					DRV_FLASH_LOG("\r\nflash write error 9, addr:%x, size:%d\r\n", _uiWriteAddr, NumOfSingle);
					return -9;
				}
			}
		}
	}
	return 0;	
}

/**
 * @brief 从flash读取数据
 * 
 * @param _pBuf 数据地址
 * @param _uiReadAddr flash地址
 * @param _uiSize 长度
 * @return uint8_t uint8_t 0：成功 <0：失败
 */
int drv_flash_read_buffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize)
{
	if (g_flash_ops.drv_flash_read_buffer(_pBuf, _uiReadAddr,  _uiSize) == false)
	{
		return -1;
	}
	return 0;
}


int drv_flash_erase_sector(uint32_t _uiReadAddr)
{
	if (g_flash_ops.drv_flash_erase_sector(_uiReadAddr) == false)
	{
		return -1;
	}
	return 0;
}

/**
 * @brief flash初始化
 * 
 * @param flash_inf_t falsh句柄 
 * @param drv_flash_erase_sector 扇区擦除接口
 * @param drv_flash_page_write 页写入接口
 * @param drv_flash_read_buffer 读取数据接口
 * @param drv_flash_lock 上锁
 * @param drv_flash_unlock 解锁
 * @return int 0：成功 <0：失败
 */
int drv_flash_register( flash_inf_def flash_inf_t,
						bool (*drv_flash_erase_sector)(uint32_t _uiSectorAddr),
                        bool (*drv_flash_page_write)(uint8_t * _pBuf, uint32_t _uiWriteAddr, uint16_t _usSize),
                        bool (*drv_flash_read_buffer)(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize),
                        uint32_t (*drv_flash_lock)(void),
                        uint32_t (*drv_flash_unlock)(uint32_t level) )
{
	if( drv_flash_erase_sector == NULL || drv_flash_page_write == NULL || drv_flash_read_buffer == NULL )
	{
		DRV_FLASH_LOG("\r\nfunction is NULL\r\n");
		return -1;
	}
	if( flash_inf_t.cache_size < flash_inf_t.SectorSize )
	{
		DRV_FLASH_LOG("\r\ncache size error, cache_size:%d, SectorSize:%d\r\n", flash_inf_t.cache_size, flash_inf_t.SectorSize);
		return -2;
	}
	if(flash_inf_t.ChipID == 0)
	{
		DRV_FLASH_LOG("\r\nChipID error, ChipID:%x\r\n", flash_inf_t.ChipID);
		return -3;
	}
	if(flash_inf_t.cache_buff == NULL)
	{
		DRV_FLASH_LOG("\r\ncache_buff is  NULL\r\n");
		return -4;
	}
	if(flash_inf_t.TotalSize < flash_inf_t.SectorSize)
	{
		DRV_FLASH_LOG("\r\nTotalSize size error, TotalSize:%d, SectorSize:%d\r\n", flash_inf_t.TotalSize, flash_inf_t.SectorSize);
		return -5;
	}
	
	g_flash_ops.drv_flash_lock			= drv_flash_lock;			
	g_flash_ops.drv_flash_unlock	    = drv_flash_unlock;	  
	g_flash_ops.drv_flash_page_write	= drv_flash_page_write;	
	g_flash_ops.drv_flash_read_buffer	= drv_flash_read_buffer;
	g_flash_ops.drv_flash_erase_sector	= drv_flash_erase_sector;
	
	g_flash_inf.cache_buff = flash_inf_t.cache_buff;
	g_flash_inf.cache_size = flash_inf_t.cache_size;
	g_flash_inf.ChipID     = flash_inf_t.ChipID    ;
	g_flash_inf.SectorSize = flash_inf_t.SectorSize;
	g_flash_inf.TotalSize  = flash_inf_t.TotalSize ;
	
	strncpy((char*)g_flash_inf.ChipName, (char*)flash_inf_t.ChipName, sizeof(g_flash_inf.ChipName));
	
	return 0;
}

